#include "kernel/externc.h"
#include "kernel/tty.h"
#include "kernel/vkey.h"

void CreateTeletype(Teletype *tty){
    tty->startRow = 0;
    CreateTerminateBuffer(tty->buffer);
}

TerminateBuffer* GetTerminateBuffer(Teletype *tty){
    return tty->buffer;
}

Buff GetBuffer(Teletype *tty){
    return tty->buffer->buffer;
}

void GetCursor(Teletype *tty, Cursor *cursor){
    cursor->curRow = tty->buffer->curRow;
    cursor->curColumn = tty->buffer->curColumn;
}

void StartNewRow(Teletype* tty){
    TerminateBuffer* terminateBuffer = tty->buffer;
    if(tty->startRow>0 && terminateBuffer->curRow-tty->startRow>=TTY_ROW){
        tty->startRow = terminateBuffer->curRow-TTY_ROW+1;
        return;
    }

    if(terminateBuffer->curRow>=TTY_ROW-1){
        int startRow = tty->startRow;
        if(startRow>=TTY_ROW){
            return;
        }
        tty->startRow = startRow+1;
    }

    terminateBuffer->curRow++;
    terminateBuffer->curColumn = 0;
}

void WriteCharacter(Teletype* tty, short k){
    TerminateBuffer* terminateBuffer = tty->buffer;
    terminateBuffer->buffer[terminateBuffer->curRow][terminateBuffer->curColumn] = k;
    if(terminateBuffer->curColumn>=BUFF_COLUMN-1){
        terminateBuffer->curRow ++;
        terminateBuffer->curColumn = 0;
    }else{
        terminateBuffer->curColumn ++;
    }
    if(tty->startRow>0 && terminateBuffer->curRow-tty->startRow>=TTY_ROW){
        tty->startRow = terminateBuffer->curRow-TTY_ROW+1;
    }
}

void DeleteLastCharacter(Teletype* tty){
    TerminateBuffer* buffer = tty->buffer;
    if(buffer->curRow==0 && buffer->curColumn==0){
        return;
    }
    if(buffer->curColumn==0){
        buffer->curRow--;
        int newColumn = BUFF_COLUMN-1;
        while(buffer->buffer[buffer->curRow][newColumn]==0 && newColumn!=-1){
            newColumn--;
        }
        buffer->curColumn = newColumn+1;
        if(tty->startRow>0){
            tty->startRow--;
        }
        return;
    }
    if(buffer->curColumn!=0){
        buffer->buffer[buffer->curRow][--buffer->curColumn]= 0;
        return;
    }
}

void TeletypeKeyPressed(Teletype *tty,int k,short kValue,int modifiers){
    // 1. buff full
    if(IsBuffFull(tty)){
        return;
    }

    // 2. key modifiers
    if(IsKeyControllers(k)){
        return;
    }

    // 3. delete a buff
    if(IsKeyBackspace(k)){
        DeleteLastCharacter(tty);
        return;
    }

    //4. new row
    if(IsKeyReturn(k)){
        if(!CheckIsPrintf(tty)){
            StartNewRow(tty);
        }
        return;
    }

    //5. home
    if(IsKeyHome(k)){
        Home(tty);
        return;
    }

    //6. end
    if(IsKeyEnd(k)){

        End(tty);
        return;
    }

    //7. page up
    if(IsKeyPageUp(k) && IsKeyControlModifiers(modifiers) ){
        PageUp(tty);
        return;
    }

    //8. page down
    if(IsKeyPageDown(k) && IsKeyControlModifiers(modifiers) ){
        PageDown(tty);
        return;
    }

    //9. normal routine
    WriteCharacter(tty, kValue);
}

Boolean CheckIsPrintf(Teletype* tty){
    TerminateBuffer* buffer = tty->buffer;
    if(buffer->curColumn<6){
        return False;
    }
    short* rowBuff = buffer->buffer[buffer->curRow];
    int index = 0;
    while(rowBuff[index]==32){
        index ++;
    }
    if(buffer->curColumn-index<6){
        return False;
    }
    if(!(rowBuff[index]=='p' && rowBuff[index+1]=='r'
         && rowBuff[index+2]=='i' && rowBuff[index+3]=='n'
         &&rowBuff[index+4]=='t' && rowBuff[index+5]=='f')){
        return False;
    }

    index = index + 6;
    while(rowBuff[index]==32){
        index ++;
    }
    if(index<buffer->curColumn){
        int column = 0;
        int row = buffer->curRow + 1;
        for(int i=index;i<buffer->curColumn;i++){
            buffer->buffer[row][column++] = buffer->buffer[buffer->curRow][index];
        }

        buffer->curRow += 2;
        buffer->curColumn = 0;
    }
    return True;
}

Boolean IsBuffFull(Teletype* tty){
    TerminateBuffer* terminateBuffer = tty->buffer;
    if(terminateBuffer->curColumn>=BUFF_COLUMN-1 && terminateBuffer->curRow>=BUFF_ROW-1){
        return True;
    }

    return False;
}

void PageUp(Teletype *tty){
    int startRow = tty->startRow;
    if(startRow<=0){
        return;
    }
    tty->startRow = startRow-1;
}

void PageDown(Teletype *tty){
    int startRow = tty->startRow;
    if(startRow>=TTY_ROW){
        return;
    }
    if(tty->buffer->curRow-startRow<=TTY_ROW-1){
        return;
    }
    tty->startRow = startRow+1;
}

void Home(Teletype *tty){
    tty->startRow = 0;
}

void End(Teletype *tty){
    int startRow = tty->startRow;
    int curRow = tty->buffer->curRow;
    if(startRow==0 && curRow<=TTY_ROW-1){
        return;
    }
    int dis = curRow-(tty->startRow+TTY_ROW-1);
    while(dis>0){
        dis--;
        tty->startRow++;
    }
}

void FreeTty(Teletype* tty){
    // TODO
}
